package com.time.client.domain.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.time.admin.common.utils.CollectionUtils;
import com.time.client.common.entity.PageResult;
import com.time.client.common.enums.IsDeletedFlagEnum;
import com.time.client.domain.converter.TagBOConverter;
import com.time.client.domain.entity.TagBO;
import com.time.client.domain.redis.RedisUtil;
import com.time.client.domain.service.ClientTagDomainService;
import com.time.client.infra.basic.entity.Tag;
import com.time.client.infra.basic.service.TagService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

/**
 * 标签管理服务层接口实现类
 *
 * @author: HuangQi
 * @date: Created in 11:13 2025/10/14
 * @description: 标签管理服务层接口实现类
 */
@Slf4j
@Service("clientTagDomainServiceImpl")
public class ClientTagDomainServiceImpl implements ClientTagDomainService {

    @Autowired
    private TagService tagService;
    @Autowired
    private RedisUtil redisUtil;

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final long TAG_CACHE_TIMEOUT_MINUTES = 20L;
    private static final long TAG_CACHE_JITTER_MINUTES = 5L;
    private static final TimeUnit TAG_CACHE_TIMEUNIT = TimeUnit.MINUTES;

    @Override
    public PageResult<TagBO> queryAllTag(TagBO tagBO) {
        if (log.isInfoEnabled()) {
            log.info("ClientTagDomainServiceImpl.queryAllTag.bo:{}", tagBO);
        }

        String cacheKey = redisUtil.buildKey("client", "tag", "queryAll", serializeKey(tagBO));
        PageResult<TagBO> cacheResult = getCache(cacheKey, new TypeReference<PageResult<TagBO>>() {});
        if (cacheResult != null) {
            return cacheResult;
        }

        // 参数转换
        Tag tag = TagBOConverter.INSTANCE.convertBOToEntity(tagBO);
        tag.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());

        // 创建分页结果
        PageResult<TagBO> pageResult = new PageResult<>();
        pageResult.setPageNo(tagBO.getPageNo());
        pageResult.setPageSize(tagBO.getPageSize());

        // 获取总记录数
        int total = tagService.countAll();
        pageResult.setTotal(total);

        // 获取分页的标签信息（使用PageResult自动计算的start）
        int start = (pageResult.getStart() - 1); // PageResult的start是从1开始的，需要转换为从0开始
        List<Tag> tagList = tagService.queryPage(tag, start, pageResult.getPageSize());

        // 参数转换
        List<TagBO> tagBOList = TagBOConverter.INSTANCE.convertEntityListToBO(tagList);

        // 设置分页结果
        pageResult.setResult(tagBOList);

        setCache(cacheKey, pageResult);
        // 返回结果
        return pageResult;
    }

    @Override
    public List<TagBO> queryHotTag() {
        if (log.isInfoEnabled()) {
            log.info("ClientTagDomainServiceImpl.queryHotTag");
        }

        String cacheKey = redisUtil.buildKey("client", "tag", "hot");
        List<TagBO> cacheResult = getCache(cacheKey, new TypeReference<List<TagBO>>() {});
        if (cacheResult != null) {
            return cacheResult;
        }

        // 获取热门标签的 id
        List<Tag> tagList = tagService.queryByHot();

        // 参数转换
        if (CollectionUtils.isEmpty(tagList)) {
            setCache(cacheKey, List.of());
            return List.of();
        }
        List<TagBO> tagBOList = TagBOConverter.INSTANCE.convertEntityListToBO(tagList);

        setCache(cacheKey, tagBOList);
        return tagBOList;
    }

    private <T> T getCache(String key, TypeReference<T> typeReference) {
        try {
            String cacheValue = redisUtil.get(key);
            if (cacheValue == null) {
                return null;
            }
            return OBJECT_MAPPER.readValue(cacheValue,
                    OBJECT_MAPPER.getTypeFactory().constructType(typeReference.getType()));
        } catch (Exception e) {
            log.warn("ClientTagDomainServiceImpl.getCache.error:key={}, msg={}", key, e.getMessage());
            return null;
        }
    }

    private void setCache(String key, Object value) {
        try {
            long ttl = TAG_CACHE_TIMEOUT_MINUTES +
                    ThreadLocalRandom.current().nextLong(TAG_CACHE_JITTER_MINUTES + 1);
            redisUtil.set(key, OBJECT_MAPPER.writeValueAsString(value), ttl, TAG_CACHE_TIMEUNIT);
        } catch (Exception e) {
            log.warn("ClientTagDomainServiceImpl.setCache.error:key={}, msg={}", key, e.getMessage());
        }
    }

    private String serializeKey(Object obj) {
        try {
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (Exception e) {
            log.warn("ClientTagDomainServiceImpl.serializeKey.error:{}", e.getMessage());
            return String.valueOf(obj);
        }
    }
}
